import { Academy } from "../Academy";
import { ActionSpec } from "../Actuators/ActionSpec";
import { ActionBuffers } from "../Actuators/IActionReceiver";
import { IActuator } from "../Actuators/IActuator";
import { AgentInfo } from "../Agent";
import { TrainingAnalytics } from "../Analytics/TrainingAnalytics";
import { ICommunicator } from "../Communicator/ICommunicator";
import { ISensor } from "../Sensors/ISensor";
import { IPolicy } from "./IPolicy";


/**
 * 远程政策，用于远程决策智能体的行为。
 * 当训练代理时，这个远程政策将被后端python控制。
 */
export class RemotePolicy implements IPolicy {
    private _agentId: number = 0;
    private _fullyQualifiedBehaviorName: string;
    private _actionSpec: ActionSpec;
    private _lastActionBuffer: ActionBuffers = null!;
    private _analyticsSent: boolean = false;

    private _communicator: ICommunicator = null!;
    private _actuators: IActuator[] = [];

    constructor(
        actionSpec: ActionSpec,
        actuators: IActuator[],
        fullyQualifiedBehaviorName: string
    ) {
        this._fullyQualifiedBehaviorName = fullyQualifiedBehaviorName;
        this._communicator = Academy.instance.communicator;
        this._communicator?.subscribeBrain(this._fullyQualifiedBehaviorName, actionSpec);
        this._actionSpec = actionSpec;
        this._actuators = actuators;
    }

    public requestDecision(info: AgentInfo, sensors: ISensor[]): void {
        this.sendAnalytics(sensors);
        this._agentId = info.episodeId;
        this._communicator?.putObservations(this._fullyQualifiedBehaviorName, info, sensors);
    }

    private sendAnalytics(sensors: ISensor[]): void {
        if (!this._analyticsSent) {
            this._analyticsSent = true;
            TrainingAnalytics.remotePolicyInitialized(
                this._fullyQualifiedBehaviorName,
                sensors,
                this._actionSpec,
                this._actuators
            );
        }
    }

    public decideAction(): ActionBuffers {
        this._communicator?.decideBatch();
        const actions = this._communicator?.getActions(this._fullyQualifiedBehaviorName, this._agentId);
        this._lastActionBuffer = actions == null ? ActionBuffers.empty() : actions as ActionBuffers;
        return this._lastActionBuffer;
    }

    public dispose(): void {
    }
}
